/**
 *    Copyright (C) 2009 Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */


#include <cubefs/api/tools/version.hpp>
#include <cubefs/api/tools/strings.hpp>
#include <cubefs/core/tools/configurator.hpp>
#include <cubefs/api/exceptions.hpp>

#include <stdlib.h>
#include <errno.h>
#include <iostream>
#include <sstream>

#define CUBEFS_SOURCE "api-impl/all/version.cpp:" CUBEFS_AT

namespace cubefs { namespace api {

using namespace cubefs::tools;

Version::Version(StringRef str): magor_(0), minor_(0), patchset_(0), timestamp_(0) {
	typedef String::size_type SizeT;
	SizeT index = 0;

	Int cnt = 0;
	while (index < str.length())
	{
		SizeT idx = str.find(".", index);
		if (idx == String::npos) idx = str.length();

		if (idx - index > 0)
		{
			Long value = StrToL(str.substr(index, idx - index));
			switch (cnt) {
			case 0: magor_ 		= value; break;
			case 1: minor_ 		= value; break;
			case 2: patchset_ 	= value; break;
			case 3: timestamp_ 	= value; break;

			default: throw CubefsException(CUBEFS_SOURCE, "Invalid version format: "+str);
			}

			cnt++;
		}
		else {
			throw CubefsException(CUBEFS_SOURCE, "Invalid version format: "+str);
		}

		index = idx + 1;
	}
}

bool Version::operator == (const Version& other) const {
	return magor_ == other.magor_ && minor_ == other.minor_ && patchset_ == other.patchset_ && timestamp_ == other.timestamp_;
}

bool Version::operator >= (const Version& other) const {
	return magor_ == other.magor_ && minor_ >= other.minor_ && patchset_ >= other.patchset_ && timestamp_ >= other.timestamp_;
}

bool Version::IsMatches(const Version& other) const
{
	return  (magor_ 	!= 0 ? magor_ 		== other.magor_ : true) &&
			(minor_  	!= 0 ? minor_ 		<= other.minor_ : true)  &&
			(patchset_ 	!= 0 ? patchset_	<= other.patchset_ : true) &&
			(timestamp_	!= 0 ? timestamp_	<= other.timestamp_ : true);
}

String Version::str() const {
	stringstream os;

	os<<GetMagor()<<"."<<GetMinor()<<"."<<GetPatchset();
	if (GetTimestamp() > 0)
	{
		os<<"."<<GetTimestamp();
	}

	return os.str();
}

}}

namespace std {

CUBEFS_API ostream& operator<<(ostream& os, const cubefs::api::Version& v) {
	os<<v.str();
	return os;
}

}
